/*
 * @Author: wuqingchun
 * @Date: 2024-04-16 08:57:15
 * @Description: 共享智能指针（资源管理器）实现
 * @LastEditors: wuqingchun
 * @LastEditTime: 2024-04-16 22:37:03
 */
#ifndef __MY_SHARED_PTR_H__
#define __MY_SHARED_PTR_H__


template <typename TP>
class shared_deleter
{
public:
    void operator()(TP* pObjPtr)
    {
        delete pObjPtr;
    }
};
/**
 * @brief 共享智能指针模板类
 * 
 * @tparam TP 指针类型
 * @tparam TD 删除器类型
 */
template <typename TP, typename TD=shared_deleter<TP>>
class my_shared_ptr
{
private:
    /* data */
    TP* m_pObjPtr {nullptr};  // 资源指针
    int* m_piRefCnt {nullptr}; // 引用计数
    TD m_objDeleter;          // 资源删除器
public:
    my_shared_ptr(TP* pObjPtr):
        m_pObjPtr(pObjPtr),
        m_piRefCnt(new int(0))
    {

    }

    // 拷贝构造函数
    my_shared_ptr(const my_shared_ptr<TP, TD>& refSP)
    {
        m_pObjPtr = refSP.m_pObjPtr;
        m_piRefCnt = refSP.m_piRefCnt;
        *m_piRefCnt++;
    }

    // 移动构造函数
    my_shared_ptr(my_shared_ptr<TP, TD>&& refSP)
    {
        m_pObjPtr = refSP.m_pObjPtr;
        m_piRefCnt = refSP.m_piRefCnt;

        refSP.m_pObjPtr = nullptr;
        refSP.m_piRefCnt = nullptr;
    }

    // 赋值运算符
    my_shared_ptr<TP, TD>& operator= (const my_shared_ptr<TP, TD>& refSP)
    {
        if (this == &refSP)
        {
            return *this;
        }

        m_pObjPtr = refSP.m_pObjPtr;
        m_piRefCnt = refSP.m_piRefCnt;
        *m_piRefCnt++;

        return *this;
    }

    // 移动赋值运算符
    my_shared_ptr<TP, TD>& operator= (my_shared_ptr<TP, TD>&& refSP)
    {
        if (this == &refSP)
        {
            return *this;
        }

        m_pObjPtr = refSP.m_pObjPtr;
        m_piRefCnt = refSP.m_piRefCnt;

        refSP.m_pObjPtr = nullptr;
        refSP.m_piRefCnt = nullptr;

        return *this;
    }


    ~my_shared_ptr()
    {
        if (m_pObjPtr != nullptr)
        {
            if (*m_piRefCnt == 0)
            {
                delete m_pObjPtr;
                m_pObjPtr = nullptr;
            }
        }
    }

    TP& operator* ()
    {
        return *m_pObjPtr;
    }

    TP* operator-> ()
    {
        return get();
    }

    TP& operator[] (size_t ulPos)
    {
        return m_pObjPtr[ulPos];
    }

    TP* get()
    {
        return m_pObjPtr;
    }

    TP* release()
    {
        if (*m_piRefCnt > 0)
        {
            *m_piRefCnt--;
        }

        TP* pObjPtr = m_pObjPtr;
        m_pObjPtr = nullptr;
        m_piRefCnt = nullptr;
        
        return pObjPtr; 
    }

    void reset()
    {
        if (*m_piRefCnt > 0)
        {
            *m_piRefCnt--;
        }
    }
};


#endif //__MY_SHARED_PTR_H__